package model

import (
	"common/helper"
	"database/sql"
	"fmt"
	"net/url"

	"github.com/StudioSol/set"
	"github.com/bytedance/gopkg/util/xxhash3"
	g "github.com/doug-martin/goqu/v9"
	"github.com/valyala/fastjson"
)

type Tag_t struct {
	Tid        string `db:"tid" cbor:"tid" json:"tid"`
	Name       string `db:"name" cbor:"name" json:"name"`
	State      string `db:"state" cbor:"state" json:"state"` //0:关闭1:开启
	CreatedAt  uint32 `db:"created_at" cbor:"created_at" json:"created_at"`
	GameType   int    `db:"game_type" cbor:"game_type" json:"game_type"`       //场馆类型
	PlatformId int    `db:"platform_id" cbor:"platform_id" json:"platform_id"` //游戏ID
}

type TagIdx_t struct {
	Id     string `db:"id" json:"id"`
	TagId  string `db:"tag_id" json:"tag_id"`
	GameId string `db:"game_id" json:"game_id"`
	Code   string `db:"code" json:"code"`
}

func tagFlushMulti(ids []string) error {

	var data []Tag_t

	t := dialect.From("tbl_game_tag_name")
	query, _, _ := t.Select("tid", "name", "created_at", "state", "game_type", "platform_id").Where(g.Ex{"id": ids}).ToSQL()
	err := meta.MerchantDB.Select(&data, query)
	if err != nil {

		return err
	}

	b, err := helper.JsonMarshal(data)
	if err != nil {

		return err
	}

	index := meta.Meili.Index("tags")
	index.DeleteDocuments(ids)
	_, err = index.AddDocuments(b, "tid")
	if err != nil {

		return err
	}
	return nil
}

func TagFlushAll() {

	var data []Tag_t

	t := dialect.From("tbl_game_tag_name")
	query, _, _ := t.Select("tid", "name", "created_at", "state", "game_type", "platform_id").Where(g.Ex{"state": "1"}).ToSQL()
	err := meta.MerchantDB.Select(&data, query)
	if err != nil && err != sql.ErrNoRows {

		return
	}

	pipe := meta.MerchantRedis.Pipeline()
	defer pipe.Close()

	for _, v := range data {
		pipe.HSet(ctx, "tags_map", v.Tid, v.Name)
	}
	pipe.Exec(ctx)

	filterable := []string{
		"game_type",
		"platform_id",
	}
	sortable := []string{
		"created_at",
	}
	searchable := []string{
		"name",
	}

	b, err := helper.JsonMarshal(data)
	if err != nil {

		return
	}

	meta.Meili.DeleteIndex("tags")
	index := meta.Meili.Index("tags")
	index.UpdateFilterableAttributes(&filterable)
	index.UpdateSortableAttributes(&sortable)
	index.UpdateSearchableAttributes(&searchable)

	_, err = index.AddDocuments(b, "tid")
	if err != nil {

		return
	}

}

func tagFlushGameTagId(gameId string) error {

	var (
		data []TagIdx_t
		ids  []string
		a    = &fastjson.Arena{}
	)

	tagMap := map[string]string{}
	ex := g.Ex{
		"game_id": gameId,
	}

	t := dialect.From("tbl_game_tag_idx")
	query, _, _ := t.Select("id", "tag_id", "game_id", "code").Where(ex).ToSQL()
	err := meta.MerchantDB.Select(&data, query)
	if err != nil && err != sql.ErrNoRows {

		return err
	}

	for _, v := range data {
		ids = append(ids, v.TagId)
	}
	ll := len(ids)

	res, err := meta.MerchantRedis.HMGet(ctx, "tags_map", ids...).Result()
	if err != nil {
		return pushLog(err, "数据库错误")
	}

	for i := 0; i < ll; i++ {
		tagId := ids[i]
		if vv, ok := res[i].(string); ok {
			tagMap[tagId] = vv
		}
	}

	aa := a.NewArray()
	for i, v := range data {

		name := tagMap[v.TagId]
		o := a.NewObject()
		o.Set("id", a.NewStringBytes([]byte(v.TagId)))
		o.Set("name", a.NewStringBytes([]byte(name)))

		aa.SetArrayItem(i, o)

	}

	ex = g.Ex{
		"id": gameId,
	}
	recs := g.Record{
		"tag_id": aa.String(),
	}
	query, _, _ = dialect.Update("tbl_game_lists").Set(recs).Where(ex).ToSQL()
	_, err = meta.MerchantDB.Exec(query)
	if err != nil {
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
	}

	return nil
}

func TagUnPin(tagId, gameId string) error {

	ex := g.Ex{
		"tag_id":  tagId,
		"game_id": gameId,
	}
	query, _, _ := dialect.Delete("tbl_game_tag_idx").Where(ex).ToSQL()
	_, err := meta.MerchantDB.Exec(query)
	if err != nil {
		return err
	}

	tagFlushGameTagId(gameId)
	GameFlushAll()
	return err
}

func TagPin(gameIds, tagIds []string) error {

	fields := []string{}
	tagMap := map[string]string{}
	tagslice := make(map[string]*set.LinkedHashSetString)

	ll := len(tagIds)

	for _, tagId := range tagIds {
		fields = append(fields, tagId)
	}
	res, err := meta.MerchantRedis.HMGet(ctx, "tags_map", fields...).Result()
	if err != nil {
		return pushLog(err, "数据库错误")
	}

	for i := 0; i < ll; i++ {
		tagId := tagIds[i]
		if vv, ok := res[i].(string); ok {
			tagMap[tagId] = vv
		}

	}

	tx, err := meta.MerchantDB.Begin()
	if err != nil {
		return pushLog(err, "数据库错误")
	}

	for _, tagId := range tagIds {

		for _, v := range gameIds {

			str := fmt.Sprintf("%s%s", v, tagId)
			code := xxhash3.HashString(str)
			data := TagIdx_t{
				Id:     helper.GenId(),
				TagId:  tagId,
				GameId: v,
				Code:   fmt.Sprintf("%d", code),
			}

			query, _, _ := dialect.Insert("tbl_game_tag_idx").Rows(&data).ToSQL()
			tx.Exec(query)
			/*
				_, err := tx.Exec(query)
				if err != nil {
					tx.Rollback()
					return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
				}
			*/
			if _, ok := tagslice[v]; !ok {
				tagslice[v] = set.NewLinkedHashSetString()
			}

			tagslice[v].Add(tagId)
		}
	}

	_ = tx.Commit()

	for _, v := range gameIds {
		tagFlushGameTagId(v)
	}
	GameFlushAll()
	//tagFlushCache()
	return nil
}

func TagList(name string, game_type, state int) ([]Tag_t, error) {

	var data []Tag_t
	ex := g.Ex{}

	if len(name) > 1 {
		decodedValue, err := url.QueryUnescape(name)
		if err != nil {
			return data, err
		}
		ex["name"] = FilterInjection(decodedValue)
	}
	if game_type > 0 {
		ex["game_type"] = fmt.Sprintf("%d", game_type)
	}
	if state == 0 || state == 1 {
		ex["state"] = fmt.Sprintf("%d", state)
	}

	t := dialect.From("tbl_game_tag_name")
	query, _, _ := t.Select("tid", "name", "created_at", "state", "game_type", "platform_id").Where(ex).Order(g.C("created_at").Desc()).ToSQL()
	err := meta.MerchantDB.Select(&data, query)
	if err != nil && err != sql.ErrNoRows {
		return data, pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
	}

	return data, nil
}

func TagInsert(data Tag_t) error {

	query, _, _ := dialect.Insert("tbl_game_tag_name").Rows(&data).ToSQL()
	_, err := meta.MerchantDB.Exec(query)
	if err != nil {
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
	}

	TagFlushAll()
	return nil
}

func TagUpdate(data Tag_t) error {

	ex := g.Ex{
		"tid": data.Tid,
	}

	record := g.Record{
		"name":        data.Name,
		"state":       data.State,
		"game_type":   data.GameType,
		"platform_id": data.PlatformId,
	}
	query, _, _ := dialect.Update("tbl_game_tag_name").Set(record).Where(ex).ToSQL()

	_, err := meta.MerchantDB.Exec(query)
	if err != nil {
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
	}

	TagFlushAll()
	return nil
}

func TagDelete(id string) error {

	var data []TagIdx_t

	ex := g.Ex{
		"tid": id,
	}

	ex1 := g.Ex{
		"tag_id": id,
	}

	query, _, _ := dialect.From("tbl_game_tag_idx").Select("id", "tag_id", "game_id", "code").Where(ex1).ToSQL()
	err := meta.MerchantDB.Select(&data, query)
	if err != nil && err != sql.ErrNoRows {
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
	}

	tx, err := meta.MerchantDB.Begin()
	if err != nil {
		return pushLog(err, "数据库错误")
	}
	query, _, _ = dialect.Delete("tbl_game_tag_name").Where(ex).ToSQL()
	_, err = tx.Exec(query)
	if err != nil {
		tx.Rollback()
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
	}

	query, _, _ = dialect.Delete("tbl_game_tag_idx").Where(ex1).ToSQL()
	_, err = tx.Exec(query)
	if err != nil {
		tx.Rollback()
		return pushLog(fmt.Errorf("%s,[%s]", err.Error(), query), "数据库错误")
	}
	_ = tx.Commit()

	for _, v := range data {
		tagFlushGameTagId(v.GameId)
	}
	TagFlushAll()
	GameFlushAll()
	return nil
}
